package com.learn.redis.singin.impl;

import com.learn.redis.singin.UserSignInService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author : 翌擎科技
 * @date : 2022/10/9 17:49
 */
@Service
@Slf4j
public class UserSignInServiceImpl implements UserSignInService {

    /**
     * https://blog.csdn.net/qq_33764524/article/details/125529897
     */
    /**
     * 用户月签到数据KEY模板
     */
    private final static String MONTH_SIGN_IN_KEY_TEMPLATE = "u:sign:%s:%s";
    /**
     * 用户指定日期连续签到天数KEY模板
     */
    private final static String CONTINUOUS_SIGN_IN_DAY_COUNT_KEY_TEMPLATE = "u:sign:%s:continuous:count:%s";
    /**
     * 保存当前连续签到排行榜
     */
    private final static String  CONTINUOUS_SIGN_RANK_KEY_TEMPLATE= "u:sign:current:continuous:rank";
    /**
     * 保存历史连续签到排行榜
     */
    private final static String  CONTINUOUS_SIGN_RANK_HIS_KEY_TEMPLATE= "u:sign:history:continuous:rank";
    /**
     * 订阅用户ID集合KEY
     */
    private final static String SUBSCRIBERS_SET_KEY = "u:sign:subscription:users";


    private final static DateTimeFormatter YYYYMM_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");
    private final static DateTimeFormatter YYYYMMDD_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public void signIn(String userId, LocalDate localDate) {

        LocalDate yesterdayDate = localDate.minusDays(1);

        String monthSingKey = String.format(MONTH_SIGN_IN_KEY_TEMPLATE, userId, YYYYMM_FORMATTER.format(localDate));
        int offset = localDate.getDayOfMonth() - 1;
        System.out.println(monthSingKey + "     " + offset);
        redisTemplate.opsForValue().setBit(monthSingKey, offset, true);

        String yesterdayContinuousSignKey = String.format(CONTINUOUS_SIGN_IN_DAY_COUNT_KEY_TEMPLATE, userId, YYYYMMDD_FORMATTER.format(yesterdayDate));
        String todayContinuousSignKey = String.format(CONTINUOUS_SIGN_IN_DAY_COUNT_KEY_TEMPLATE, userId, YYYYMMDD_FORMATTER.format(localDate));
        String continuous = redisTemplate.opsForValue().get(yesterdayContinuousSignKey);
        long signCount = 1;
        if (StringUtils.isNotBlank(continuous)){
            signCount = signCount + Long.parseLong(continuous);
        }
        redisTemplate.opsForValue().set(todayContinuousSignKey, String.valueOf(signCount));
        redisTemplate.opsForZSet().add(CONTINUOUS_SIGN_RANK_KEY_TEMPLATE,userId,signCount);
        redisTemplate.opsForZSet().add(CONTINUOUS_SIGN_RANK_HIS_KEY_TEMPLATE,userId,signCount);
    }

    @Override
    public void cancelSignIn(String userId, LocalDate localDate) {
        String monthSingKey = String.format(MONTH_SIGN_IN_KEY_TEMPLATE, userId, YYYYMM_FORMATTER.format(localDate));
        int offset = localDate.getDayOfMonth() - 1;
        redisTemplate.opsForValue().setBit(monthSingKey, offset, false);

        String todayContinuousSignKey = String.format(CONTINUOUS_SIGN_IN_DAY_COUNT_KEY_TEMPLATE, userId, YYYYMMDD_FORMATTER.format(localDate));
        redisTemplate.delete(todayContinuousSignKey);
    }

    @Override
    public Boolean checkSignIn(String userId, LocalDate localDate) {
        String monthSingKey = String.format(MONTH_SIGN_IN_KEY_TEMPLATE, userId, YYYYMM_FORMATTER.format(localDate));
        int offset = localDate.getDayOfMonth() - 1;
        Boolean isSign = redisTemplate.opsForValue().getBit(monthSingKey, offset);
        log.info("{}",isSign);
        return Objects.nonNull(isSign) && isSign;
    }

    @Override
    public long getContinuousSignInCount(String userId, LocalDate localDate) {
        LocalDate targetDate = localDate;
        if (!checkSignIn(userId, localDate)) {
            targetDate = localDate.minusDays(1);
        }
        String singDays = String.format(CONTINUOUS_SIGN_IN_DAY_COUNT_KEY_TEMPLATE, userId, YYYYMMDD_FORMATTER.format(targetDate));
        return StringUtils.isBlank(singDays) ? 0 : Long.parseLong(singDays);
    }

    @Override
    public LocalDate getFirstSignMonth(String userId, LocalDate localDate) {
        String monthSingKey = String.format(MONTH_SIGN_IN_KEY_TEMPLATE, userId, YYYYMM_FORMATTER.format(localDate));

        //TODO 待完成

        return null;
    }

    @Override
    public Map<String, Boolean> getSignMonth(String userId, LocalDate localDate) {
        return null;
    }

    @Override
    public void subscribeSignInTip(String userId) {
        redisTemplate.opsForSet().add(SUBSCRIBERS_SET_KEY, userId);
    }

    @Override
    public void unSubscribeSignInTip(String userId) {
        redisTemplate.opsForSet().remove(SUBSCRIBERS_SET_KEY, userId);
    }

    @Override
    public Boolean checkSubscribeSignInTip(String userId) {
        return redisTemplate.opsForSet().isMember(SUBSCRIBERS_SET_KEY,userId);
    }

    @Override
    public List<String> getUnSignInSubscribers(LocalDate localDate) {
        Set<String> members = redisTemplate.opsForSet().members(SUBSCRIBERS_SET_KEY);
        if (CollectionUtils.isNotEmpty(members)) {
            return members.stream().filter(r -> !checkSignIn(r, localDate)).collect(Collectors.toList());
        }
        return null;
    }


    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        String format = YYYYMM_FORMATTER.format(LocalDate.now());
        System.out.println(format);

        String format1 = String.format(MONTH_SIGN_IN_KEY_TEMPLATE, "CD001", YYYYMM_FORMATTER.format(LocalDate.now()));

        System.out.println(format1);

        int offset = localDate.getDayOfMonth() - 1;
        System.out.println(offset);
    }
}
